import { Tile } from "./tile";

export class Grid {
  size: any; //网格数量 size*size
  cells: any[][] = [[]]; //二维数组
  constructor(size: any, previousState?: any) {
    this.size = size;
    this.cells = previousState ? this.fromState(previousState) : this.empty();
  }

  // Build a grid of the specified size
  empty() {
    const cells = [];
    /*
    [[{x:0,y:0},{x:0,y:1},{x:0,y:2},{x:0,y:3}],
     [{x:1,y:0},{x:1,y:1},{x:1,y:2},{x:1,y:3}],
     [{x:2,y:0},{x:2,y:1},{x:2,y:2},{x:2,y:3}],
     [{x:3,y:0},{x:3,y:1},{x:3,y:2},{x:3,y:3}]]
    */
    for (let x = 0; x < this.size; x++) {
      const row: any = cells[x] = [];

      for (let y = 0; y < this.size; y++) {
        row.push(null);
      }
    }

    return cells;
  }

  fromState(state: any[][]) {
    const cells = [];

    for (let x = 0; x < this.size; x++) {
      const row: any = cells[x] = [];

      for (let y = 0; y < this.size; y++) {
        const tile = state[x][y];
        row.push(tile ? new Tile(tile.position, tile.value) : null);
      }
    }

    return cells;
  }

  // Find the first available random position
  randomAvailableCell() {
    const cells = this.availableCells();

    if (cells.length) {
      return cells[Math.floor(Math.random() * cells.length)];
    }
  }

  // 返回所有可用单元格
  availableCells() {
    const cells: any[] = [];

    this.eachCell((x: any, y: any, tile: any) => {
      if (!tile) {
        // 返回没有被占用的砖块坐标
        cells.push({ x, y });
      }
    });

    return cells;
  }

  // 遍历获取size边界内所有单元格
  eachCell(callback: { (x: any, y: any, tile: any): void; (arg0: number, arg1: number, arg2: never): void; }) {
    for (let x = 0; x < this.size; x++) {
      for (let y = 0; y < this.size; y++) {
        callback(x, y, this.cells[x][y]);
      }
    }
  }

  // 检查是否还有可用单元格
  cellsAvailable() {
    return !!this.availableCells().length;
  }

  // 检查单元是否可用
  cellAvailable(cell: any) {
    return !this.cellOccupied(cell);
  }

  // 检查单元格是否被占领
  cellOccupied(cell: any) {
    return !!this.cellContent(cell);
  }

  // 获取单元格内容
  cellContent(cell: { x: number; y: number; }) {
    if (this.withinBounds(cell)) {
      return this.cells[cell.x][cell.y];
    } else {
      return null;
    }
  }

  // Inserts a tile at its position
  insertTile(tile: { x: number; y: number; }) {
    this.cells[tile.x][tile.y] = tile;
  }

  removeTile(tile: { x: number; y: number; }) {
    this.cells[tile.x][tile.y] = null;
  }

  withinBounds(position: { x: any; y: any; }) {
    return position.x >= 0 && position.x < this.size &&
      position.y >= 0 && position.y < this.size;
  }

  serialize() {
    const cellState = [];

    for (let x = 0; x < this.size; x++) {
      const row: any = cellState[x] = [];

      for (let y = 0; y < this.size; y++) {
        row.push(this.cells[x][y] ? this.cells[x][y].serialize() : null);
      }
    }

    return {
      size: this.size,
      cells: cellState
    };
  }
}